/********************************** (C) COPYRIGHT *******************************
 * File Name          : MCU.c
 * Author             : WCH
 * Version            : V1.2
 * Date               : 2022/01/18
 * Description        : 硬件任务处理函数及BLE和硬件初始化
 * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
 * SPDX-License-Identifier: Apache-2.0
 *******************************************************************************/

/******************************************************************************/
/* 头文件包�? */
#include "HAL.h"
#include "gattprofile.h"

tmosTaskID halTaskId = INVALID_TASK_ID;

shutterCommand_t *command;

uint16_t total = 0;

char totalStr[20];

uint16_t interval =0;

uint16_t na = 0;

extern uint8_t menu_index;

extern menu_t menu_table[19];

UINT8 ResponseData[SHUTTERPROFILE_CHAR_NOTIFY_LEN]={0};

/*******************************************************************************
 * @fn      Lib_Calibration_LSI
 *
 * @brief   内部32k校准
 *
 * @param   None.
 *
 * @return  None.
 */
void Lib_Calibration_LSI(void)
{
    Calibration_LSI(Level_64);
}

#if(defined(BLE_SNV)) && (BLE_SNV == TRUE)
/*******************************************************************************
 * @fn      Lib_Read_Flash
 *
 * @brief   Lib 操作Flash回调
 *
 * @param   addr.
 * @param   num.
 * @param   pBuf.
 *
 * @return  None.
 */
uint32_t Lib_Read_Flash(uint32_t addr, uint32_t num, uint32_t *pBuf)
{
    EEPROM_READ(addr, pBuf, num * 4);
    return 0;
}

/*******************************************************************************
 * @fn      Lib_Write_Flash
 *
 * @brief   Lib 操作Flash回调
 *
 * @param   addr.
 * @param   num.
 * @param   pBuf.
 *
 * @return  None.
 */
uint32_t Lib_Write_Flash(uint32_t addr, uint32_t num, uint32_t *pBuf)
{
    EEPROM_ERASE(addr, EEPROM_PAGE_SIZE * 2);
    EEPROM_WRITE(addr, pBuf, num * 4);
    return 0;
}
#endif

/*******************************************************************************
 * @fn      CH57X_BLEInit
 *
 * @brief   BLE 库初始化
 *
 * @param   None.
 *
 * @return  None.
 */
void CH58X_BLEInit(void)
{
    uint8_t     i;
    bleConfig_t cfg;
    if(tmos_memcmp(VER_LIB, VER_FILE, strlen(VER_FILE)) == FALSE)
    {
        // PRINT("head file error...\r\n");
        while(1);
    }
    SysTick_Config(SysTick_LOAD_RELOAD_Msk);
    PFIC_DisableIRQ(SysTick_IRQn);

    tmos_memset(&cfg, 0, sizeof(bleConfig_t));
    cfg.MEMAddr = (uint32_t)MEM_BUF;
    cfg.MEMLen = (uint32_t)BLE_MEMHEAP_SIZE;
    cfg.BufMaxLen = (uint32_t)BLE_BUFF_MAX_LEN;
    cfg.BufNumber = (uint32_t)BLE_BUFF_NUM;
    cfg.TxNumEvent = (uint32_t)BLE_TX_NUM_EVENT;
    cfg.TxPower = (uint32_t)BLE_TX_POWER;
#if(defined(BLE_SNV)) && (BLE_SNV == TRUE)
    cfg.SNVAddr = (uint32_t)BLE_SNV_ADDR;
    cfg.readFlashCB = Lib_Read_Flash;
    cfg.writeFlashCB = Lib_Write_Flash;
#endif
#if(CLK_OSC32K)
    cfg.SelRTCClock = (uint32_t)CLK_OSC32K;
#endif
    cfg.ConnectNumber = (PERIPHERAL_MAX_CONNECTION & 3) | (CENTRAL_MAX_CONNECTION << 2);
    cfg.srandCB = SYS_GetSysTickCnt;
#if(defined TEM_SAMPLE) && (TEM_SAMPLE == TRUE)
    cfg.tsCB = HAL_GetInterTempValue; // 根据温度变化校准RF和内部RC( 大于7摄氏�? )
  #if(CLK_OSC32K)
    cfg.rcCB = Lib_Calibration_LSI; // 内部32K时钟校准
  #endif
#endif
#if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
    cfg.WakeUpTime = WAKE_UP_RTC_MAX_TIME;
    cfg.sleepCB = CH58X_LowPower; // 启用睡眠
#endif
#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
    for(i = 0; i < 6; i++)
    {
        cfg.MacAddr[i] = MacAddr[5 - i];
    }
#else
    {
        uint8_t MacAddr[6];
        GetMACAddress(MacAddr);
        for(i = 0; i < 6; i++)
        {
            cfg.MacAddr[i] = MacAddr[i]; // 使用芯片mac地址
        }
    }
#endif
    if(!cfg.MEMAddr || cfg.MEMLen < 4 * 1024)
    {
        while(1);
    }
    i = BLE_LibInit(&cfg);
    if(i)
    {
        // PRINT("LIB init error code: %x ...\r\n", i);
        while(1);
    }
}

/*******************************************************************************
 * @fn      HAL_ProcessEvent
 *
 * @brief   硬件层事务处�?
 *
 * @param   task_id - The TMOS assigned task ID.
 * @param   events  - events to process.  This is a bit map and can
 *                      contain more than one event.
 *
 * @return  events.
 */
tmosEvents HAL_ProcessEvent(tmosTaskID task_id, tmosEvents events)
{
    uint8_t *msgPtr;
    if (events & HAL_KEY_EVENT) //按键扫描
    {
        uint8 key = HAL_KeyPoll();
        if (key)
        {
            if(menu_index<19)
            {
                switch(key)
                {
                case HAL_KEY_SW_UP:
                    menu_index = menu_table[menu_index].up_index;
                    menu_table[menu_index].pFunction();
                    break;
                case HAL_KEY_SW_DOWN:
                    menu_index = menu_table[menu_index].down_index;
                    menu_table[menu_index].pFunction();
                    break;
                case HAL_KEY_SW_ENTER:
                    if(menu_index == 6 || menu_index == 9 || menu_index == 12 ||menu_index == 16){
                        menu_index = menu_table[menu_index].back_index;
                    }else{
                        menu_index = menu_table[menu_index].enter_index;
                    }
                    menu_table[menu_index].pFunction();
                    break;
                default:
                    break;
                }
            }
            tmos_start_task(halTaskId, HAL_KEY_EVENT, MS1_TO_SYSTEM_TIME(25));
        }else
        {
            tmos_start_task(halTaskId, HAL_KEY_EVENT, MS1_TO_SYSTEM_TIME(25)); //定时25ms后再次启动本任务，每25ms扫描一次按�?
        }
        return events ^ HAL_KEY_EVENT;
    }
    if(events & HAL_OLED_REFRESH_EVENT)
    {
        OLED_Refresh_Gram();
        tmos_start_task(halTaskId, HAL_OLED_REFRESH_EVENT, MS1_TO_SYSTEM_TIME(200));
    }
    if(events & SYS_EVENT_MSG)
    { // 处理HAL层消息，调用tmos_msg_receive读取消息，处理完成后删除消息�?
        if((msgPtr = tmos_msg_receive(task_id)) != NULL){
            command = (shutterCommand_t *)msgPtr;
            if(command->start == 0xFFFE && command->end == 0xFEFF){
                OLED_Clear_Ram();
                switch(command->cmd){
                    case COMMAND_POWER:
                        tmos_set_event(halTaskId,HAL_CAMERA_POWER_ON_EVENT);
                        break;
                    case COMMAND_FOCUS:
                        GPIOB_SetBits(CAMERA_FOCUS);
                        OLED_ShowText(47, 8, "对焦", 16,1);
                        OLED_Refresh_Gram();
                        break;
                    case COMMAND_UNFOCUS:
                        GPIOB_ResetBits(CAMERA_FOCUS);
                        OLED_ShowText(31, 8, "取消对焦", 16,1);
                        OLED_Refresh_Gram();
                        break;
                    case COMMAND_SHUTTER:
                        {
                            if(command->interval == 0){
                                OLED_Clear_Ram();
                                OLED_ShowText(47, 8, "拍照", 16,1);
                                HAL_CameraShutterPress();
                            }else{
                                interval = command->interval;
                                OLED_Clear_Ram();
                                OLED_ShowString(47, 8, "Bulb", 16,1);
                                HAL_CameraShutterHold();
                                HAL_CameraShutterRelease(interval);
                            }
                        }
                        break;
                    case COMMAND_TIMELAPSE:
                        total = command->total;
                        interval = command->interval;
                        na = command->na;
                        OLED_Clear_Ram();
                        sprintf(totalStr, "%d", total);
                        OLED_ShowText(0, 7, "剩余", 16,1);
                        OLED_ShowString(32, 7, totalStr, 16, 1);
                        OLED_ShowText(63, 7, "总数", 16,1);
                        OLED_ShowString(95, 7, totalStr, 16, 1);
                        tmos_start_reload_task(halTaskId, HAL_CAMERA_TIMELAPSE_EVENT, MS1_TO_SYSTEM_TIME(1000 * interval));
                        break;
                    case COMMAND_UNTIMELAPSE:
                        OLED_Clear_Ram();
                        OLED_ShowText(15, 8, "取消延时摄影", 16,1);
                        ResponseData[3]=0x00;
                        ResponseData[4]=0x00;
                        ResponseData[5]=0x00;
                        ResponseData[6]=0x00;
                        ResponseData[7]=0x00;
                        tmos_stop_task(halTaskId, HAL_CAMERA_TIMELAPSE_EVENT);
                        break;
                    default:
                        break;
                }
            }
            tmos_msg_deallocate(msgPtr);
        }
        return events ^ SYS_EVENT_MSG;
    }
    if(events & HAL_CAMERA_SHUTTER_OFF_EVENT)
    {
        GPIOB_ResetBits(CAMERA_SHUTTER);
        DelayMs(1);
        GPIOB_ResetBits(CAMERA_FOCUS);
        return events ^ HAL_CAMERA_SHUTTER_OFF_EVENT;
    }
    if(events & HAL_CAMERA_POWER_ON_EVENT)
    {
        GPIOB_SetBits(CAMERA_POWER);
        OLED_Clear_Ram();
        OLED_ShowText(47, 8, "关机", 16,1);
        OLED_Refresh_Gram();
        tmos_start_task(halTaskId, HAL_CAMERA_POWER_OFF_EVENT, MS1_TO_SYSTEM_TIME(1000));
        return events ^ HAL_CAMERA_POWER_ON_EVENT;
    }
    if(events & HAL_CAMERA_POWER_OFF_EVENT)
    {
        GPIOB_ResetBits(CAMERA_POWER);
        return events ^ HAL_CAMERA_POWER_OFF_EVENT;
    }
    if(events & HAL_CAMERA_TIMELAPSE_EVENT)
    {
        total--;
        ResponseData[0]=0xFF;
        ResponseData[1]=0xFE;
        ResponseData[2]=0x05;
        if(total <= 0){
            ResponseData[3]=0x00;
            ResponseData[4]=0x00;
            ResponseData[5]=0x00;
            ResponseData[6]=0x00;
            ResponseData[7]=0x00;
        }else{
            ResponseData[3]=0x01;
            ResponseData[4]=HI_UINT16(total);
            ResponseData[5]=LO_UINT16(total);
            ResponseData[6]=HI_UINT16(interval);
            ResponseData[7]=LO_UINT16(interval);
        }
        ResponseData[8]=HI_UINT16(na);
        ResponseData[9]=LO_UINT16(na);
        ResponseData[10]=0xFE;
        ResponseData[11]=0xFF;
        HAL_CameraShutterPress();
        OLED_Clear_Ram();
        char surplus[20];
        sprintf(surplus, "%d", total);
        OLED_ShowText(0, 7, "剩余", 16,1);
        OLED_ShowString(32, 7, surplus, 16, 1);
        OLED_ShowText(63, 7, "总数", 16,1);
        OLED_ShowString(95, 7, totalStr, 16, 1);
        if(total <= 0)
        {
            OLED_Clear_Ram();
            OLED_ShowText(0, 7, "星火计划蓝牙快门", 16, 1);
            tmos_stop_task(halTaskId, HAL_CAMERA_TIMELAPSE_EVENT);
        }
        return events ^ HAL_CAMERA_TIMELAPSE_EVENT;
    }
    if(events & HAL_REG_INIT_EVENT)
    {
#if(defined BLE_CALIBRATION_ENABLE) && (BLE_CALIBRATION_ENABLE == TRUE) // 校准任务，单次校准耗时小于10ms
        BLE_RegInit();                                                  // 校准RF
  #if(CLK_OSC32K)
        Lib_Calibration_LSI(); // 校准内部RC
  #endif
        tmos_start_task(halTaskId, HAL_REG_INIT_EVENT, MS1_TO_SYSTEM_TIME(BLE_CALIBRATION_PERIOD));
        return events ^ HAL_REG_INIT_EVENT;
#endif
    }
    return 0;
}

/*******************************************************************************
 * @fn      HAL_Init
 *
 * @brief   硬件初始�?
 *
 * @param   None.
 *
 * @return  None.
 */
void HAL_Init()
{
    halTaskId = TMOS_ProcessEventRegister(HAL_ProcessEvent);
    HAL_TimeInit();
    GPIOAGPPCfg(DISABLE, RB_PIN_USB_IE);
    GPIOAGPPCfg(DISABLE, RB_PIN_USB2_IE);
#if(defined HAL_SLEEP) && (HAL_SLEEP == TRUE)
    HAL_SleepInit();
#endif
#if(defined HAL_SHUTTER) && (HAL_SHUTTER == TRUE)
    HAL_ShutterInit();
    HAL_SPIInit();
    OLED_Init();
    HAL_KeyInit();
    //启动按键扫描事件
    tmos_start_task(halTaskId, HAL_KEY_EVENT, MS1_TO_SYSTEM_TIME(25));
#endif
    OLED_ShowText(0, 7, "星火计划蓝牙快门", 16, 1);
    tmos_set_event(halTaskId, HAL_OLED_REFRESH_EVENT);
#if(defined BLE_CALIBRATION_ENABLE) && (BLE_CALIBRATION_ENABLE == TRUE)
    tmos_start_task(halTaskId, HAL_REG_INIT_EVENT, MS1_TO_SYSTEM_TIME(BLE_CALIBRATION_PERIOD)); // 添加校准任务，单次校准耗时小于10ms
#endif
}

/*******************************************************************************
 * @fn      HAL_GetInterTempValue
 *
 * @brief   获取内部温感采样值，如果使用了ADC中断采样，需在此函数中暂时屏蔽中�?.
 *
 * @return  内部温感采样�?.
 */
uint16_t HAL_GetInterTempValue(void)
{
    uint8_t  sensor, channel, config, tkey_cfg;
    uint16_t adc_data;

    tkey_cfg = R8_TKEY_CFG;
    sensor = R8_TEM_SENSOR;
    channel = R8_ADC_CHANNEL;
    config = R8_ADC_CFG;
    ADC_InterTSSampInit();
    R8_ADC_CONVERT |= RB_ADC_START;
    while(R8_ADC_CONVERT & RB_ADC_START);
    adc_data = R16_ADC_DATA;
    R8_TEM_SENSOR = sensor;
    R8_ADC_CHANNEL = channel;
    R8_ADC_CFG = config;
    R8_TKEY_CFG = tkey_cfg;
    return (adc_data);
}

/******************************** endfile @ mcu ******************************/
